package ocr

import (
	"bytes"
	"net"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/otiai10/gosseract/v2"
	"github.com/panjf2000/ants/v2"
	"github.com/enriquebris/goconcurrentqueue"

	"gitee.com/guoliben/kydlp-doctotext/utils/ctrlledprint"
	"gitee.com/guoliben/kydlp-doctotext/extractor_interface"
)

var multiProcessMode bool = false

type OcrFileTask struct {
	ImagePath string
	ImageSize int64
	ImageType string
}

type OcrBufferTask struct {
	ImageData []byte
	ImageSize int64
	ImageType string
}

type OcrTaskResult struct {
	Context interface{}
	ImagePath string
	ImageSize int64
	ImageType string
	Elapsed string
	Text string
	Error error
}

var (
	ocrOnce sync.Once

	maxconcurrencynumofocrpool = (runtime.NumCPU() + 1) / 2
	maxbuffersizeofchan = maxconcurrencynumofocrpool
	maxsizeoftaskqueue = maxconcurrencynumofocrpool

	useFIFO = true
	ocrFileQueue goconcurrentqueue.Queue
	ocrBufferQueue goconcurrentqueue.Queue

	unixSocketPath = "/opt/kydlp-control-discovery/sock/ocr-ipc.sock"
	listener net.Listener

	OcrWg sync.WaitGroup
	OcrConcurrencyPool *ants.Pool
	OcrBufferedChan = make(chan OcrTaskResult, maxbuffersizeofchan) // 带缓冲的通道，用于存储OCR处理结果
)

func WgCounterIncrement(delta int) {
	// 增加计数器的值。delta 可以是正数或负数，用于设置或调整等待的 goroutine 数量
	OcrWg.Add(delta)
}

func WgCounterDecrement() {
	// 减少 WaitGroup 计数器的值，实际上是调用 Add(-1)
	defer OcrWg.Done()
}

func WgBlockUntilOcrDone() {
	// 阻塞当前 goroutine，直到 WaitGroup 的计数器减为0，即所有 goroutine 都执行完毕
	// 也即等待所有OCR任务完成
	OcrWg.Wait()
}

func CloseChanAfterOcrDone() {
	// 关闭带缓冲的通道，表示不再有新的OCR结果，通知主goroutine所有OCR任务已完成
	close(OcrBufferedChan)
}

/**
* 获取并打印所有OCR结果
*/
func GetAndPrintAllOcrResult() {
	// 循环接收数据
	// 使用 for range 循环来不断从channel中接收数据，直到channel被关闭
	for result := range OcrBufferedChan {
		ctrlledprint.Println()
		if result.Error == nil {
			ctrlledprint.Println("OCR提取:", "成功")
		} else {
			ctrlledprint.Println("OCR提取出错:", result.Error)
		}
		ctrlledprint.Println("OCR提取:", result.ImagePath, "结果:")
		ctrlledprint.Println("OCR提取耗时:", result.Elapsed)
		ctrlledprint.Println("OCR提取到的文本:", result.Text)
	}
}

/**
* 获取一个OCR结果
*/
func GetOcrResult() (interface{}, string, int64, string, string, string) {
	// select语句会阻塞，直到channel接收到数据或者default分支被执行
	select {
	case result := <-OcrBufferedChan:
		return result.Context, result.ImagePath, result.ImageSize, result.ImageType, result.Text, result.Elapsed

		//case <-time.After(time.Second): // 带超时的select语句
		//	ctrlledprint.Println("No data received within timeout")

		//default: // 如果没有数据可读，default分支会被执行 
		//	ctrlledprint.Println("No data received")
	}
}

func Init(ocrEngineSwitch bool) error {
	if ocrEngineSwitch {
		ctrlledprint.Println("初始化OCR引擎...")

		value := os.Getenv("USE_MULTIPROCESS_MODE")
		if len(value) > 0 {
			value = strings.ToLower(strings.TrimSpace(value))
			switch value {
			case "true", "1", "yes", "on":
				multiProcessMode = true
			case "false", "0", "no", "off":
				multiProcessMode = false
			default:
				multiProcessMode = false
			}
		} else {
			multiProcessMode = false
		}

		var err error

		if multiProcessMode {
			ocrOnce.Do(func() {
				if OcrConcurrencyPool == nil {
					// 创建一个ants池，设置并发数
					OcrConcurrencyPool, err = ants.NewPool(maxconcurrencynumofocrpool) // 占用两个goroutine
					if err != nil {
						ctrlledprint.Println("\t创建OCR并发池失败:", err)
						return
					} else {
						ctrlledprint.Println("\t创建OCR并发池成功!")
					}
				} else {
					ctrlledprint.Println("\tOCR引擎已初始化!")
				}
				if ocrFileQueue == nil {
					if useFIFO {
						ocrFileQueue = goconcurrentqueue.NewFIFO()
					} else {
						ocrFileQueue = goconcurrentqueue.NewFixedFIFO(maxsizeoftaskqueue)
					}
					if ocrFileQueue != nil {
						ctrlledprint.Println("\t创建OCR(file)任务队列成功!", "OCR任务队列初始容量:", ocrFileQueue.GetCap())
					} else {
						ctrlledprint.Println("\t创建OCR(file)任务队列失败!")
						return
					}
				}
				if ocrBufferQueue == nil {
					if useFIFO {
						ocrBufferQueue = goconcurrentqueue.NewFIFO()
					} else {
						ocrBufferQueue = goconcurrentqueue.NewFixedFIFO(maxsizeoftaskqueue)
					}
					if ocrBufferQueue != nil {
						ctrlledprint.Println("\t创建OCR(buffer)任务队列成功!", "OCR任务队列初始容量:", ocrBufferQueue.GetCap())
					} else {
						ctrlledprint.Println("\t创建OCR(buffer)任务队列失败!")
						return
					}
				}
				go createOcrBufferTransformServer()
			})
		} else {
			ocrOnce.Do(func() {
				if OcrConcurrencyPool == nil {
					// 创建一个ants池，设置并发数
					OcrConcurrencyPool, err = ants.NewPool(maxconcurrencynumofocrpool) // 占用两个goroutine
					if err != nil {
						ctrlledprint.Println("\t创建OCR并发池失败:", err)
						return
					} else {
						ctrlledprint.Println("\t创建OCR并发池成功!")
					}
				} else {
					ctrlledprint.Println("\tOCR引擎已初始化!")
				}
			})
		}

		ctrlledprint.Println("完成OCR引擎初始化!")
		return nil
	}

	return nil
}

func createOcrBufferTransformServer() {
	// 删除旧的本地套接字文件
	err := os.Remove(unixSocketPath)
	if err != nil && !os.IsNotExist(err) {
		ctrlledprint.Println("\t删除旧的套接字文件出错:", err)
	}
	// 创建Unix域套接字
	listener, err = net.Listen("unix", unixSocketPath)
	if err != nil {
		ctrlledprint.Println("\t创建OCR(buffer)任务传输服务端监听器出错:", err)
		return
	} else {
		ctrlledprint.Println("\t创建OCR(buffer)任务传输服务端监听器成功!", "Listening on:", unixSocketPath)
	}
	for {
		// 接受客户端连接
		conn, err := listener.Accept()
		if err != nil {
			ctrlledprint.Println("\t服务器端退出或接收客户端连接出错:", err)
			break
		} else {
			// 打印客户端的地址
			ctrlledprint.Println("\t服务器端接收客户端连接成功!", "连接来自:", conn.RemoteAddr().String())
		}

		// 处理连接
		go handleConnection(conn)
	}
}

func handleConnection(conn net.Conn) {
	defer conn.Close()

	// 从OCR(buffer)任务队列取出一个任务，并向客户端发送该任务
	if OcrConcurrencyPool != nil && ocrBufferQueue != nil {
		ctrlledprint.Println("<--- OCR(buffer)任务队列容量:", ocrBufferQueue.GetCap(), "已经入队的任务数:", ocrBufferQueue.GetLen())
		ocrtask, err := ocrBufferQueue.Dequeue()
		if err != nil {
			ctrlledprint.Println("OCR(buffer)任务出队失败:", err)
			return
		} else {
			ctrlledprint.Println("OCR(buffer)任务出队成功!")
		}
		ocrbuffertask := ocrtask.(OcrBufferTask)

		start := time.Now()

		n, err := conn.Write(ocrbuffertask.ImageData)
		if err != nil {
			ctrlledprint.Println("OCR(buffer)任务传输出错:", err)
			return
		}

		elapsed := time.Since(start)

		ctrlledprint.Println("OCR(buffer)任务传输完成!", "大小:", n, "耗时:", elapsed)
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}
}

func Destroy() {
	if multiProcessMode {
		if ocrFileQueue != nil {
			ctrlledprint.Println("OCR(file)任务队列容量:", ocrFileQueue.GetCap(), "已经入队的任务数:", ocrFileQueue.GetLen())
		}
		if ocrBufferQueue != nil {
			ctrlledprint.Println("OCR(buffer)任务队列容量:", ocrBufferQueue.GetCap(), "已经入队的任务数:", ocrBufferQueue.GetLen())
		}
		if listener != nil {
			defer listener.Close() // 关闭后在调用listener.Accept会异常退出！
		}
	}
	if OcrConcurrencyPool != nil {
		// 打印协程池统计信息
		ctrlledprint.Println("Ants running goroutines: ", OcrConcurrencyPool.Running())
		ctrlledprint.Println("Ants total tasks: ", OcrConcurrencyPool.Cap())

		defer OcrConcurrencyPool.Release()
	}
}

func createOcrClient() *gosseract.Client {
	ocrclient := gosseract.NewClient()
	if ocrclient == nil {
		ctrlledprint.Printf("创建OCR引擎客户端失败!")
		return nil
	}

	//languages, err := ocrclient.GetAvailableLanguages()
	//if err != nil {
	//	ctrlledprint.Printf("Failed to get available languages: %v\n", err)
	//	return nil
	//}
	//ctrlledprint.Println("List of available languages in the default tesspath:")
	//for _, language := range languages {
	//	ctrlledprint.Println("|---", language)
	//}

	//languages_needed := []string{"chi_sim", "chi_tra"}
	//ocrClient.SetLanguage(languages_needed...)

	languages := []string{"chi_sim"}

	var languages_needed []string
	for _, language := range languages {
		if language == "chi_sim" {
			languages_needed = append(languages_needed, "chi_sim")
			ctrlledprint.Println("OCR引擎gosseract支持简体中文字符识别!")
		}
		if language == "chi_tra" {
			languages_needed = append(languages_needed, "chi_tra")
			ctrlledprint.Println("OCR引擎gosseract支持繁体中文字符识别!")
		}
	}
	if len(languages_needed) > 0 {
		ocrclient.SetLanguage(languages_needed...)
	}

	return ocrclient
}

func ocrProcessFromFile(path string, size int64, filetype string, context interface{}) {
	if OcrConcurrencyPool != nil {
		ocrClient := createOcrClient()
		if ocrClient == nil {
			return
		}
		defer ocrClient.Close()

		/**
		* 每次调用client.SetImage都会替换之前设置的图片，
		* 这意味着如果多个goroutine同时调用client.SetImage，它们可能会互相覆盖。
		* 你应该确保client.SetImage的调用是线程安全的，或者每个goroutine使用自己的client实例。
		*/
		start := time.Now()
		ocrClient.SetImage(path)
		text, err := ocrClient.Text()
		elapsed := time.Since(start)

		//ocrClient.DestroyImage()

		OcrBufferedChan <- OcrTaskResult{
			Context: context,
			ImagePath: path,
			ImageSize: size,
			ImageType: filetype,
			Elapsed: elapsed.String(),
			Text: text,
			Error: err,
		}

		ctrlledprint.Println("OCR(file)光学字符识别完成，耗时:", elapsed)
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}
}

func ocrProcessFromBuffer(path string, data []byte, size int64, filetype string, context interface{}) {
	if OcrConcurrencyPool != nil {
		ocrClient := createOcrClient()
		if ocrClient == nil {
			return
		}
		defer ocrClient.Close()

		/**
		* 每次调用client.SetImageFromBytes都会替换之前设置的图片，
		* 这意味着如果多个goroutine同时调用client.SetImageFromBytes，它们可能会互相覆盖。
		* 你应该确保client.SetImage的调用是线程安全的，或者每个goroutine使用自己的client实例。
		*/
		start := time.Now()
		ocrClient.SetImageFromBytes(data)
		text, err := ocrClient.Text()
		elapsed := time.Since(start)

		//ocrClient.DestroyImage()

		OcrBufferedChan <- OcrTaskResult{
			Context: context,
			ImagePath: path,
			ImageSize: size,
			ImageType: filetype,
			Elapsed: elapsed.String(),
			Text: text,
			Error: err,
		}

		ctrlledprint.Println("OCR(buffer)光学字符识别完成，耗时:", elapsed)
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}
}

// 子进程函数，调用Tesseract命令进行图片OCR
func ocrProcessFile(path string) (string, error) {
	// 构建Tesseract OCR命令及其参数
	cmd := exec.Command("tesseract", path, "stdout", "-l", "chi_sim")

	// 缓冲区用于存储命令的输出
	var out bytes.Buffer
	var errOut bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &errOut

	// 执行命令并等待其完成
	if err := cmd.Run(); err != nil {
		ctrlledprint.Println("执行Tesseract命令出错:", errOut.String())
		return "", err
	} else {
		ctrlledprint.Println("执行Tesseract命令成功，输出:", out.String())
		return out.String(), nil
	}
}

// 子进程函数，调用kydlp-tasktransfer命令进行图片OCR
func ocrProcessBuffer() (string, error) {
	// 构建OCR任务处理器命令及其参数
	cmd := exec.Command("/opt/kydlp-control-discovery/bin/kydlp-tasktransfer", "--socket", unixSocketPath, "--task", "ocrtask", "--buffer")

	// 缓冲区用于存储命令的输出
	var out bytes.Buffer
	var errOut bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &errOut

	// 执行命令并等待其完成
	if err := cmd.Run(); err != nil {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理OCR(buffer)任务出错:", errOut.String())
		return "", err
	} else {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理OCR(buffer)任务成功，输出:", out.String())
		return out.String(), nil
	}
}

func ocrProcessFileFromQueue(context interface{}) {
	if OcrConcurrencyPool != nil && ocrFileQueue != nil {
		ctrlledprint.Println("<--- OCR(file)任务队列容量:", ocrFileQueue.GetCap(), "已经入队的任务数:", ocrFileQueue.GetLen())
		ocrtask, err := ocrFileQueue.Dequeue()
		if err != nil {
			ctrlledprint.Println("OCR(file)任务:", ocrtask, "出队失败:", err)
			return
		} else {
			ctrlledprint.Println("OCR(file)任务:", ocrtask, "出队成功!")
		}
		ocrfiletask := ocrtask.(OcrFileTask)

		start := time.Now()

		text, err := ocrProcessFile(ocrfiletask.ImagePath)

		elapsed := time.Since(start)

		OcrBufferedChan <- OcrTaskResult{
			Context: context,
			ImagePath: ocrfiletask.ImagePath,
			ImageSize: ocrfiletask.ImageSize,
			ImageType: ocrfiletask.ImageType,
			Elapsed: elapsed.String(),
			Text: text,
			Error: err,
		}

		ctrlledprint.Println("OCR(file)光学字符识别完成，耗时:", elapsed)
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}
}

func ocrProcessBufferFromQueue(path string, size int64, filetype string, context interface{}) {
	start := time.Now()

	text, err := ocrProcessBuffer()

	elapsed := time.Since(start)

	// TODO: 从任务队列里取出的和这里的path、size以及filetype能确定是同一张图片吗？
	OcrBufferedChan <- OcrTaskResult{
		Context: context,
		ImagePath: path,
		ImageSize: size,
		ImageType: filetype,
		Elapsed: elapsed.String(),
		Text: text,
		Error: err,
	}

	ctrlledprint.Println("OCR(buffer)光学字符识别完成，耗时:", elapsed)
}

type OcrEngine struct{}

func (extractor OcrEngine) GetTextFromFile(path string, size int64, filetype string, depth int) ([]byte, string) {
	if OcrConcurrencyPool != nil {
		ctrlledprint.Println("提取文本: 正在异步并发OCR(file)图片...")

		WgCounterIncrement(1)

		err := OcrConcurrencyPool.Submit(func() { // 最多占用 maxconcurrencynumofocrpool 个goroutine

			ocrProcessFromFile(path, size, filetype, nil)

			//time.Sleep(time.Second) // 协程并发控制: 每秒钟最多并发执行 maxconcurrencynumofocrpool 个任务

			WgCounterDecrement()
		})
		if err != nil {
			ctrlledprint.Println("提交OCR(file)任务", path, "到并发池失败:", err)
		} else {
			ctrlledprint.Println("提交OCR(file)任务", path, "到并发池成功!")
		}
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}

	return nil, ""
}

func (extractor OcrEngine) GetTextFromBuffer(path string, data []byte, size int64, filetype string, depth int) ([]byte, string) {
	if OcrConcurrencyPool != nil {
		ctrlledprint.Println("提取文本: 正在异步并发OCR(buffer)图片...")

		WgCounterIncrement(1)

		err := OcrConcurrencyPool.Submit(func() { // 最多占用 maxconcurrencynumofocrpool 个goroutine

			ocrProcessFromBuffer(path, data, size, filetype, nil)

			//time.Sleep(time.Second) // 协程并发控制: 每秒钟最多并发执行 maxconcurrencynumofocrpool 个任务

			WgCounterDecrement()
		})
		if err != nil {
			ctrlledprint.Println("提交OCR(buffer)任务到并发池失败:", err)
		} else {
			ctrlledprint.Println("提交OCR(buffer)任务到并发池成功!")
		}
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}

	return nil, ""
}

func (extractor OcrEngine) GetStringTextFromFile(path string, size int64, filetype string, depth int) (string, string) {
	if OcrConcurrencyPool != nil {
		ctrlledprint.Println("提取文本: 正在异步并发OCR(file)图片...")

		WgCounterIncrement(1)

		err := OcrConcurrencyPool.Submit(func() { // 最多占用 maxconcurrencynumofocrpool 个goroutine

			ocrProcessFromFile(path, size, filetype, nil)

			//time.Sleep(time.Second) // 协程并发控制: 每秒钟最多并发执行 maxconcurrencynumofocrpool 个任务

			WgCounterDecrement()
		})
		if err != nil {
			ctrlledprint.Println("提交OCR(file)任务", path, "到并发池失败:", err)
		} else {
			ctrlledprint.Println("提交OCR(file)任务", path, "到并发池成功!")
		}
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}

	return "", ""
}

func (extractor OcrEngine) GetStringTextFromBuffer(path string, data []byte, size int64, filetype string, depth int) (string, string) {
	if OcrConcurrencyPool != nil {
		ctrlledprint.Println("提取文本: 正在异步并发OCR(buffer)图片...")

		WgCounterIncrement(1)

		err := OcrConcurrencyPool.Submit(func() { // 最多占用 maxconcurrencynumofocrpool 个goroutine

			ocrProcessFromBuffer(path, data, size, filetype, nil)

			//time.Sleep(time.Second) // 协程并发控制: 每秒钟最多并发执行 maxconcurrencynumofocrpool 个任务

			WgCounterDecrement()
		})
		if err != nil {
			ctrlledprint.Println("提交OCR(buffer)任务到并发池失败:", err)
		} else {
			ctrlledprint.Println("提交OCR(buffer)任务到并发池成功!")
		}
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}

	return "", ""
}

func getTextFromFileWithContext(path string, size int64, filetype string, context interface{}) ([]byte, string) {
	if OcrConcurrencyPool != nil && ocrFileQueue != nil {
		ctrlledprint.Println("提取文本: 正在异步并发OCR(file)图片...")

		ocrtask := OcrFileTask{
			ImagePath: path,
			ImageSize: size,
			ImageType: filetype,
		}
		err := ocrFileQueue.Enqueue(ocrtask)
		if err != nil {
			ctrlledprint.Println("OCR(file)任务:", ocrtask, "入队失败:", err)
			return nil, ""
		} else {
			ctrlledprint.Println("OCR(file)任务:", ocrtask, "入队成功!")
		}
		ctrlledprint.Println("---> OCR(file)任务队列容量:", ocrFileQueue.GetCap(), "已经入队的任务数:", ocrFileQueue.GetLen())

		WgCounterIncrement(1)

		err = OcrConcurrencyPool.Submit(func() { // 最多占用 maxconcurrencynumofocrpool 个goroutine

			ocrProcessFileFromQueue(context)

			//time.Sleep(time.Second) // 协程并发控制: 每秒钟最多并发执行 maxconcurrencynumofocrpool 个任务

			WgCounterDecrement()
		})
		if err != nil {
			ctrlledprint.Println("提交OCR(file)任务", path, "到并发池失败:", err)
		} else {
			ctrlledprint.Println("提交OCR(file)任务", path, "到并发池成功!")
		}
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}

	return nil, ""
}

func getTextFromBufferWithContext(path string, data []byte, size int64, filetype string, context interface{}) ([]byte, string) {
	if OcrConcurrencyPool != nil && ocrBufferQueue != nil {
		ctrlledprint.Println("提取文本: 正在异步并发OCR(buffer)图片...")

		ocrtask := OcrBufferTask{
			ImageData: data,
			ImageSize: size,
			ImageType: filetype,
		}
		err := ocrBufferQueue.Enqueue(ocrtask)
		if err != nil {
			ctrlledprint.Println("OCR(buffer)任务入队失败:", err)
			return nil, ""
		} else {
			ctrlledprint.Println("OCR(buffer)任务入队成功!")
		}
		ctrlledprint.Println("---> OCR(buffer)任务队列容量:", ocrBufferQueue.GetCap(), "已经入队的任务数:", ocrBufferQueue.GetLen())

		WgCounterIncrement(1)

		err = OcrConcurrencyPool.Submit(func() { // 最多占用 maxconcurrencynumofocrpool 个goroutine

			ocrProcessBufferFromQueue(path, size, filetype, context)

			//time.Sleep(time.Second) // 协程并发控制: 每秒钟最多并发执行 maxconcurrencynumofocrpool 个任务

			WgCounterDecrement()
		})
		if err != nil {
			ctrlledprint.Println("提交OCR(buffer)任务到并发池失败:", err)
		} else {
			ctrlledprint.Println("提交OCR(buffer)任务到并发池成功!")
		}
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}

	return nil, ""
}

func getStringTextFromFileWithContext(path string, size int64, filetype string, context interface{}) (string, string) {
	if OcrConcurrencyPool != nil && ocrFileQueue != nil {
		ctrlledprint.Println("提取文本: 正在异步并发OCR(file)图片...")

		ocrtask := OcrFileTask{
			ImagePath: path,
			ImageSize: size,
			ImageType: filetype,
		}
		err := ocrFileQueue.Enqueue(ocrtask)
		if err != nil {
			ctrlledprint.Println("OCR(file)任务:", ocrtask, "入队失败:", err)
			return "", ""
		} else {
			ctrlledprint.Println("OCR(file)任务:", ocrtask, "入队成功!")
		}
		ctrlledprint.Println("---> OCR(file)任务队列容量:", ocrFileQueue.GetCap(), "已经入队的任务数:", ocrFileQueue.GetLen())

		WgCounterIncrement(1)

		err = OcrConcurrencyPool.Submit(func() { // 最多占用 maxconcurrencynumofocrpool 个goroutine

			ocrProcessFileFromQueue(context)

			//time.Sleep(time.Second) // 协程并发控制: 每秒钟最多并发执行 maxconcurrencynumofocrpool 个任务

			WgCounterDecrement()
		})
		if err != nil {
			ctrlledprint.Println("提交OCR(file)任务", path, "到并发池失败:", err)
		} else {
			ctrlledprint.Println("提交OCR(file)任务", path, "到并发池成功!")
		}
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}

	return "", ""
}

func getStringTextFromBufferWithContext(path string, data []byte, size int64, filetype string, context interface{}) (string, string) {
	if OcrConcurrencyPool != nil && ocrBufferQueue != nil {
		ctrlledprint.Println("提取文本: 正在异步并发OCR(buffer)图片...")

		ocrtask := OcrBufferTask{
			ImageData: data,
			ImageSize: size,
			ImageType: filetype,
		}
		err := ocrBufferQueue.Enqueue(ocrtask)
		if err != nil {
			ctrlledprint.Println("OCR(buffer)任务入队失败:", err)
			return "", ""
		} else {
			ctrlledprint.Println("OCR(buffer)任务入队成功!")
		}
		ctrlledprint.Println("---> OCR(buffer)任务队列容量:", ocrBufferQueue.GetCap(), "已经入队的任务数:", ocrBufferQueue.GetLen())

		WgCounterIncrement(1)

		err = OcrConcurrencyPool.Submit(func() { // 最多占用 maxconcurrencynumofocrpool 个goroutine

			ocrProcessBufferFromQueue(path, size, filetype, context)

			//time.Sleep(time.Second) // 协程并发控制: 每秒钟最多并发执行 maxconcurrencynumofocrpool 个任务

			WgCounterDecrement()
		})
		if err != nil {
			ctrlledprint.Println("提交OCR(buffer)任务到并发池失败:", err)
		} else {
			ctrlledprint.Println("提交OCR(buffer)任务到并发池成功!")
		}
	} else {
		ctrlledprint.Println("未设置OCR引擎开关，或已设置OCR引擎开关但未启用OCR引擎，请做检查!")
	}

	return "", ""
}

func (extractor OcrEngine) GetTextFromFileWithCallback(path string, size int64, filetype string, depth int, callback extractor_interface.OnTextDetectHandler, context interface{}) (int, []byte, string) {
	var retcode int
	var text []byte
	var elapsed string

	if multiProcessMode {
		text, elapsed = getTextFromFileWithContext(path, size, filetype, context)
	} else {
		text, elapsed = extractor.GetTextFromFile(path, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}

func (extractor OcrEngine) GetTextFromBufferWithCallback(path string, data []byte, size int64, filetype string, depth int, callback extractor_interface.OnTextDetectHandler, context interface{}) (int, []byte, string) {
	var retcode int
	var text []byte
	var elapsed string

	if multiProcessMode {
		text, elapsed = getTextFromBufferWithContext(path, data, size, filetype, context)
	} else {
		text, elapsed = extractor.GetTextFromBuffer(path, data, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}

func (extractor OcrEngine) GetStringTextFromFileWithCallback(path string, size int64, filetype string, depth int, callback extractor_interface.OnStringTextDetectHandler, context interface{}) (int, string, string) {
	var retcode int
	var text, elapsed string

	if multiProcessMode {
		text, elapsed = getStringTextFromFileWithContext(path, size, filetype, context)
	} else {
		text, elapsed = extractor.GetStringTextFromFile(path, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}

func (extractor OcrEngine) GetStringTextFromBufferWithCallback(path string, data []byte, size int64, filetype string, depth int, callback extractor_interface.OnStringTextDetectHandler, context interface{}) (int, string, string) {
	var retcode int
	var text, elapsed string

	if multiProcessMode {
		text, elapsed = getStringTextFromBufferWithContext(path, data, size, filetype, context)
	} else {
		text, elapsed = extractor.GetStringTextFromBuffer(path, data, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}
